#necessary since settings is not yet defined when we need to patch it
import sys
sys.path.append('../')
import settings
import pickle
import simplejson as sj
import urllib
import urllib2
import random
rand = random.SystemRandom()


RSA_KEY = getattr(settings,'AUTH_RSA',None)
if not RSA_KEY:
    raise Exception('Unable to load public RSA key.')
DSA_KEY = getattr(settings,'AUTH_DSA',None)
if not DSA_KEY:
    raise Exception('Unable to load DSA key.')
url = 'http://localhost:8080/'
rsa = pickle.loads(RSA_KEY)
dsa = pickle.loads(DSA_KEY)

def generate_auth_key(key):
    return rsa.encrypt(key,'')[0].encode('base64')
def get_dsa_pub():
    return sj.dumps(dsa.publickey().__getstate__())

def getrandlong(dsa):
    return long(rand.randrange(2,dsa.q))

def generate_dsa_key(key):
    def f():
        return sj.dumps(dsa.sign(key,getrandlong(dsa)))
    return f

def authenticate(clientname):
    encode = urllib.urlencode
    urlopen = urllib2.urlopen
    data = {}
    data['clientname'] = clientname
    key = urlopen(url,encode(data)).read()
    
    if key.startswith('Error:'):
        raise Exception(key)

    data['clientaction'] = 'verify_key'
    data['key'] = generate_auth_key(key)
    data['dsapub'] = get_dsa_pub()
    key = urlopen(url,encode(data)).read()
    if key.startswith('Error:'):
        raise exception(key)
    d = {'clientname':clientname,
         'clientaction':'verify_session',
         'keyfunc':generate_dsa_key(key)
        }
    return d

def listcommands():
    return urllib2.urlopen(url).read()
def callfunc(d,command,args):
    urlopen = urllib2.urlopen
    encode = urllib.urlencode
    c = d.copy()
    c['key'] = c['keyfunc']()
    del c['keyfunc']

    newurl = '%s%s/'%(url,command)

    c['args'] = sj.dumps(args)
    try:
        ret = sj.loads(urlopen(newurl,encode(c)).read())
    except:
        return 
    if type(ret) == type(''):
        if ret.startswith("Error"):
            raise Exception(ret)
    if type(ret) == type([]):
        if ret[0] < 0:
            raise Exception(ret[1])
    return ret
    
def get_profile(d,username):
    return callfunc(d,'get_account',(username,))[1]

def auth_token(d,username,token):
    return callfunc(d,'verify_session',(username,token))


def set_wrapper(f,d,username):
    def func(self,name,value):
        try:
            profile = getprofile(d,username)
        except:
            raise Exception('Not able to save user.')
        try:
            profile[name] = value
            setprofile(d,username,profile)
            f(name,value)
        except:
            raise Exception('Not able to set value.')
    return func

def create_user(username,email='',d=None):
    try:
        from django.contrib.auth.models import User
        user = User.objects.get(username=username)
    except:
        user = User.objects.create_user(username,email)
    if d:
        for item in d:
            if not item.startswith('_'):
                setattr(user,item,d[item])
    return user




    
